/*
 * Copyright (C) Jahia Ltd. All rights reserved.
 *
 * This software is published under the terms of the Jahia Open Software
 * License version 1.1, a copy of which has been included with this
 * distribution in the LICENSE.txt file.
 */
package org.jahia.sqlprofiler;

import java.io.*;
import org.apache.regexp.RE;
import org.apache.regexp.RESyntaxException;
import java.util.*;
import org.jahia.sqlparser.*;
import antlr.*;
import antlr.collections.AST;
import java.text.NumberFormat;
import org.apache.commons.cli.*;

/**
 * <p>Title: SQL Profiler log file parser/p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2003</p>
 * <p>Company: Jahia Ltd</p>
 * @author Serge Huber
 * @version 1.0
 */

public class LogFileParser {

    private static final String GENERATED_INDEXES_FILE = "indexes.sql";

    private QueryStatistics queryStats = new QueryStatistics();

    public LogFileParser() {
    }

    public void parseFile(String fileName, boolean displayQueries,
                          boolean generateIndexes) throws FileNotFoundException,
        IOException, RESyntaxException {

        File inputFile = new File(fileName);
        long fileLength = inputFile.length();
        BufferedReader in
            = new BufferedReader(new FileReader(fileName));
        System.out.print("Processing file : " + fileName + "...");
        RE selectWithOrderQuery = new RE("select[:blank:].*[:blank:]from[:blank:].*[:blank:]where[:blank:](.*)[:blank:]order[:blank:]by(.*)([:blank:](asc)|(desc))?");
        RE selectQuery = new RE(
            "select[:blank:].*[:blank:]from[:blank:].*[:blank:]where[:blank:](.*)");
        String curLine = null;
        String lowerCurLine = null;
        int lineCount = 0;
        long curFilePos = 0;
        int lastCompletion = 0;
        do {
            curLine = in.readLine();
            if (curLine == null) {
                break;
            }
            curFilePos += curLine.getBytes().length;
            lineCount++;
            lowerCurLine = curLine.toLowerCase();
            String occurenceString = null;
            if (selectWithOrderQuery.match(lowerCurLine)) {
                occurenceString = selectWithOrderQuery.getParen(0);
            } else if (selectQuery.match(lowerCurLine)) {
                occurenceString = selectQuery.getParen(0);
            }
            if (occurenceString != null) {
                QueryEntry queryEntry = new QueryEntry();
                queryEntry.setSqlStatement(occurenceString);
                queryStats.processSQL(queryEntry);
            }
            double completionPercentage = (100.0 * curFilePos) / fileLength;
            int roundedCompletion = new Double(completionPercentage).intValue();
            if ( ( (roundedCompletion % 10) == 0) &&
                (lastCompletion != roundedCompletion)) {
                System.out.print(roundedCompletion + "%...");
                lastCompletion = roundedCompletion;
            }

        } while (curLine != null);
        System.out.println("100%");


        System.out.println("Lines read=" + lineCount + " occurencesFound=" +
                           queryStats.getOccurenceCount());
    }

    private void displayOccurenceStats(boolean displayQueries) {
        Iterator queryStatByOccurenceIter = queryStats.getQueryStatsByOccurence().iterator();
        while (queryStatByOccurenceIter.hasNext()) {
            QueryStatEntry curQueryStat = (QueryStatEntry)
                queryStatByOccurenceIter.next();
            double occurencePourcentage = (100.0 * curQueryStat.getOccurences()) /
                queryStats.getOccurenceCount();
            NumberFormat nf = NumberFormat.getInstance();
            nf.setMaximumFractionDigits(2);
            System.out.println(nf.format(occurencePourcentage) +
                               "% Occurences=" + curQueryStat.getOccurences() +
                               " Table(s)=" + curQueryStat.getTableNames() +
                               " Column(s)=" + curQueryStat.getColumnNames());

            if (displayQueries) {
                Iterator queryIter = curQueryStat.getQueries().iterator();
                while (queryIter.hasNext()) {
                    String curQuery = (String) queryIter.next();
                    System.out.println("    " + curQuery);
                }
            }
        }
    }


    public static void main(String[] args) {
        LogFileParser logfileParser = new LogFileParser();
        // create the command line parser
        CommandLineParser parser = new PosixParser();
        boolean displayQueries = false;
        boolean generateIndexes = false;
        String indexesFileName = GENERATED_INDEXES_FILE;

        // create the Options
        Options options = new Options();
        Option indexesOption = OptionBuilder.withLongOpt("indexes")
            .hasOptionalArg()
            .withArgName("filename")
            .withDescription("the file name to which to output the indexes ")
            .create('i');
        options.addOption("q", "with-queries", false,
            "Display the queries along with the table and column statistics");
        options.addOption(indexesOption);
        options.addOption("h", "help", false,
                          "Print this help message");

        try {
            // parse the command line arguments
            CommandLine line = parser.parse(options, args);

            if (line.hasOption('h') || (args.length == 0)) {
                HelpFormatter helpFormatter = new HelpFormatter();
                StringWriter strWriter = new StringWriter();
                PrintWriter ptrWriter = new PrintWriter(strWriter);
                helpFormatter.printHelp(ptrWriter, 80,
                    "java -jar sqlprofiler.jar log_file_name [options]", "",
                    options, 10, 10, "");
                System.out.println(strWriter.toString());
                System.exit(0);
            }

            if (line.hasOption('q')) {
                displayQueries = true;
                System.out.println("Query display activated.");
            }

            if (line.hasOption('i')) {
                generateIndexes = true;
                String optionIndexesFileName = line.getOptionValue('i');
                if (optionIndexesFileName != null) {
                    indexesFileName = optionIndexesFileName;
                }
                System.out.println("Indexes generation in file [" +
                                   indexesFileName + "] activated.");
            }

        } catch (ParseException exp) {
            System.out.println("Unexpected exception:");
            exp.printStackTrace();
            System.exit(0);
        }
        try {
            logfileParser.parseFile(args[0], displayQueries, generateIndexes);
            logfileParser.displayOccurenceStats(displayQueries);
        } catch (FileNotFoundException fnfe) {
            fnfe.printStackTrace();
        } catch (IOException ioe) {
            ioe.printStackTrace();
        } catch (RESyntaxException rese) {
            rese.printStackTrace();
        }

        if (generateIndexes) {
            System.out.print("Writing indexes SQL to file [" + indexesFileName +
                             "]...");
            try {
                FileWriter fileWriter = new FileWriter(indexesFileName);
                PrintWriter writer = new PrintWriter(fileWriter);
                Iterator indexNameIter = logfileParser.queryStats.getGeneratedIndexes().
                    keySet().iterator();
                while (indexNameIter.hasNext()) {
                    String curIndexName = (String) indexNameIter.next();
                    String indexSql = (String) logfileParser.queryStats.getGeneratedIndexes().
                        get(curIndexName);
                    writer.println(indexSql);
                }
                writer.flush();
                writer.close();
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
            System.out.println("done.");
        }
    }


}